package com.novax.ex.activity.provider.handler.consumer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.novax.ex.activity.infrastructure.entity.TaskEtRewards;
import com.novax.ex.activity.infrastructure.entity.TaskEtRewardsConfig;
import com.novax.ex.activity.provider.api.BrokerInvitationRelationshipApi;
import com.novax.ex.activity.provider.api.model.FinanceRecordEntity;
import com.novax.ex.activity.provider.api.model.InvitationResponse;
import com.novax.ex.activity.provider.api.model.NewPriceEntity;
import com.novax.ex.activity.provider.api.model.UnlockAmounts;
import com.novax.ex.activity.provider.api.model.UserResponse;
import com.novax.ex.activity.provider.handler.provider.ActivityUnlockProvider;
import com.novax.ex.activity.provider.service.TaskEtRewardsConfigService;
import com.novax.ex.activity.provider.service.TaskEtRewardsService;
import com.novax.ex.common.constant.ActivitySpoKeyConstants;
import com.novax.ex.common.constant.Currency;
import com.novax.ex.common.core.redis.RedisDistributedLocker;
import com.novax.ex.common.core.redis.RedisLockUtil;
import com.novax.ex.common.core.redis.RedisUtil;
import com.novax.ex.common.enums.TaskEtRewardsConfigTypeSwitch;
import com.novax.ex.common.results.ReturnResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.novax.ex.common.constant.MqConstants;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Description: 活动冻结ET解锁consumer
 *
 * @author shaw
 * @date 2023/6/27 11:27
 */
@Slf4j
@Component
public class ActivityUnlockConsumer {

    @Resource
    private TaskEtRewardsConfigService taskEtRewardsConfigService;

    @Resource
    private TaskEtRewardsService taskEtRewardsService;

    @Resource
    private RedisDistributedLocker redisLocker;

    @Resource
    private ActivityUnlockProvider activityUnlockProvider;

    @Resource
    private BrokerInvitationRelationshipApi brokerInvitationRelationshipApi;

    /**
     * 被邀请人 现货交易冻结ET解锁计算
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConstants.Queue.SPOT_EX_UNFROZEN, durable = "true"),
            exchange = @Exchange(value = MqConstants.Exchange.SPOT_TOPIC_INVITATION, type = ExchangeTypes.TOPIC),
            key = MqConstants.Exchange.SPOT_INVITATION_KEY)
    )
    public void spotUnlock(String message){
        try {
            // et解锁难度配置
            TaskEtRewardsConfig taskEtRewardsConfig = taskEtRewardsConfigService.find(null);
            if(taskEtRewardsConfig == null || taskEtRewardsConfig.getSpotSwitch().equals(TaskEtRewardsConfigTypeSwitch.close.getStatus())){
                return;
            }

            FinanceRecordEntity feeRecord = JSONObject.parseObject(message, FinanceRecordEntity.class);
            if(feeRecord.getAmount().compareTo(BigDecimal.ZERO) >= 0){
                return;
            }

            // userId
            Long userId = feeRecord.getUserId();

            // 计算解锁金额
            UnlockAmounts unlockAmounts = calculateUnlockAmount(feeRecord, taskEtRewardsConfig);
            BigDecimal unlockAmountInvitee = unlockAmounts.getUnlockAmountInvitee();
            BigDecimal unlockAmountInviter = unlockAmounts.getUnlockAmountInviter();
            if (unlockAmountInvitee.compareTo(BigDecimal.ZERO) <= 0) {
                return;
            }

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("unlockAmount", unlockAmountInviter);
            jsonObject.put("userId", userId);

            // 邀请人解冻
            activityUnlockProvider.inviterUnlock(jsonObject.toJSONString());

            // 锁id
            String key = RedisLockUtil.Activity.USER_REWARDS + userId;
            boolean userRewardsLock = redisLocker.tryLock(key, false);
            try {
                if(userRewardsLock){
                    updateUnlockET(userId, unlockAmountInvitee);
                }
            } catch (Exception e) {
                // 异常时打印消息体
                log.error("------------------合约 被邀请人返现异常" + JSON.toJSONString(feeRecord),e);
            } finally {
                redisLocker.unlock(key);
            }
        } catch (AmqpException e) {
            log.info("------------------用户解锁活动任务奖励 异常 合约" + JSON.toJSONString(message));
            log.info("com.aliex.ex.resource.provider.handler.TaskCenterListener", e);
        }

    }

    /**
     * @Description: 更新解锁ET
     * @Author: ChenXi
     * @Date:  2023/6/28 11:12
     * @param userId
     * @param unlockAmountInvitee
     * @return: void
     **/
    private void updateUnlockET(Long userId, BigDecimal unlockAmountInvitee) {
        TaskEtRewards taskEtRewards = taskEtRewardsService.findByUserId(userId, Currency.ET);
        if (taskEtRewards == null) {
            return ;
        }

        // 已无未解锁冻结ET
        BigDecimal currentAmount = taskEtRewards.getTotalFreeze().subtract(taskEtRewards.getUnfreeze());
        if (currentAmount.compareTo(BigDecimal.ZERO) == 0) {
            return ;
        }

        // 解锁数量不能大于未解锁的ET总量
        BigDecimal amount;
        if (unlockAmountInvitee.compareTo(currentAmount) >= 0) {
            amount = currentAmount;
        } else {
            amount = unlockAmountInvitee;
        }

        //更新活动解冻余额
        taskEtRewardsService.addUnfreeze(userId, amount, taskEtRewards.getCurrency());

        FinanceRecordEntity financeRecord = new FinanceRecordEntity();
        financeRecord.setAmount(amount);
        financeRecord.setUserId(userId);
        financeRecord.setCurrency(Currency.ET);
        financeRecord.setSymbol(Currency.ET);
        financeRecord.setOrderId(0L);
        activityUnlockProvider.rewardUnlockSend(JSON.toJSONString(financeRecord));
    }

    /**
     * 被邀请人 合约交易冻结ET解锁计算
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(value = MqConstants.Queue.SWAP_EX_UNFROZEN, durable = "true"),
            exchange = @Exchange(value = MqConstants.Exchange.SWAP_TOPIC_INVITATION, type = ExchangeTypes.TOPIC),
            key = MqConstants.Exchange.SWAP_INVITATION_KEY)
    )
    public void swapUnlock(String message){
        try {
            // et解锁难度配置
            TaskEtRewardsConfig taskEtRewardsConfig = taskEtRewardsConfigService.find(null);
            if(taskEtRewardsConfig == null || taskEtRewardsConfig.getSwapSwitch().equals(TaskEtRewardsConfigTypeSwitch.close.getStatus())){
                return;
            }
            
            FinanceRecordEntity feeRecord = JSONObject.parseObject(message, FinanceRecordEntity.class);
            if(feeRecord.getAmount().compareTo(BigDecimal.ZERO) >= 0){
                return;
            }

            // userId
            Long userId = feeRecord.getUserId();

            // 计算解锁金额
            UnlockAmounts unlockAmounts = calculateUnlockAmount(feeRecord, taskEtRewardsConfig);
            BigDecimal unlockAmountInvitee = unlockAmounts.getUnlockAmountInvitee();
            BigDecimal unlockAmountInviter = unlockAmounts.getUnlockAmountInviter();
            if (unlockAmountInvitee.compareTo(BigDecimal.ZERO) <= 0) {
                return;
            }

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("unlockAmount", unlockAmountInviter);
            jsonObject.put("userId", userId);

            // 邀请人解冻
            activityUnlockProvider.inviterUnlock(jsonObject.toJSONString());

            // 锁id
            String key = RedisLockUtil.Activity.USER_REWARDS + userId;
            boolean userRewardsLock = redisLocker.tryLock(key, false);
            try {
                if(userRewardsLock){
                    updateUnlockET(userId, unlockAmountInvitee);
                }
            } catch (Exception e) {
                // 异常时打印消息体
                log.info("------------------合约 被邀请人返现异常" + JSON.toJSONString(feeRecord));
            } finally {
                redisLocker.unlock(key);
            }
        } catch (AmqpException e) {
            log.info("------------------用户解锁活动任务奖励 异常 合约" + JSON.toJSONString(message));
            log.info("com.aliex.ex.resource.provider.handler.TaskCenterListener", e);
        }
    }

    /**
     * 邀请人解锁计算
     */
    @RabbitListener(queuesToDeclare = @Queue(value = MqConstants.Queue.SPOT_INVITER_UNFROZEN, durable = "true"))
    public void inviterUnlock(String message) {

        try {
            JSONObject jsonObject = JSONObject.parseObject(message);
            Long inviteeId = jsonObject.getLong("userId");
            // 查邀请关系
            ArrayList<Long> inviteeIdList = new ArrayList<>();
            inviteeIdList.add(inviteeId);
            ReturnResult<List<InvitationResponse>> invitedListResult = brokerInvitationRelationshipApi.getInvitedList(inviteeIdList);
            if(Objects.isNull(invitedListResult) || !invitedListResult.isSuccess()){
                return;
            }
            List<InvitationResponse> invitedList = invitedListResult.getData();
            if (invitedList.isEmpty() || Objects.isNull(invitedList.get(0)) || invitedList.get(0).getUserId().equals(0L)) {
                return;
            }

            // 邀请人ID
            Long userId = invitedList.get(0).getUserId();

            BigDecimal unlockAmount = jsonObject.getBigDecimal("unlockAmount");

            // 锁id
            String key = RedisLockUtil.Activity.USER_REWARDS + userId;
            boolean userRewardsLock = redisLocker.tryLock(key, false);
            try {
                if (userRewardsLock) {
                    // 更新解锁ET
                    updateUnlockET(userId, unlockAmount);
                }
            } catch (AmqpException e) {
                // 异常时打印消息体
                log.info("------------------用户上级活动解锁 异常" + jsonObject.toJSONString());
            } finally {
                redisLocker.unlock(key);
            }
        } catch (AmqpException e) {
            log.info("------------------用户上级活动解锁 异常" + JSON.toJSONString(message));
            log.info("com.aliex.ex.resource.provider.handler.TaskUnlockListener", e);
        }

    }



    /**
     * @Description: 计算解锁金额
     * @Author: ChenXi
     * @Date:  2023/6/28 11:45
     * @param feeRecord
     * @param taskEtRewardsConfig
     * @return: com.novax.ex.activity.provider.api.model.UnlockAmounts
     **/
    private UnlockAmounts calculateUnlockAmount(FinanceRecordEntity feeRecord, TaskEtRewardsConfig taskEtRewardsConfig) {
        // 计算兑换金额 ET
        BigDecimal exchangeAmount = getExchangeAmount(feeRecord.getAmount().negate(), feeRecord.getCurrency(),
                                                      feeRecord.getSymbol(), feeRecord.getPrice(), Currency.ET);
        // 比例
        BigDecimal ratio = taskEtRewardsConfig.getFee().multiply(new BigDecimal("0.01"));

        BigDecimal unlockAmountInvitee = exchangeAmount.multiply(ratio).multiply(new BigDecimal("0.8")).setScale(16, RoundingMode.DOWN);
        BigDecimal unlockAmountInviter = exchangeAmount.multiply(ratio).multiply(new BigDecimal("0.2")).setScale(16, RoundingMode.DOWN);

        return new UnlockAmounts(unlockAmountInvitee, unlockAmountInviter);
    }

    /**
     * @Description: 计算兑换金额
     * @Author: ChenXi
     * @Date:  2023/6/27 18:26
     * @param amount
     * @param currency
     * @param symbol
     * @param price
     * @param platformCurrency
     * @return: java.math.BigDecimal
     **/
    private BigDecimal getExchangeAmount(BigDecimal amount, String currency, String symbol, BigDecimal price, String platformCurrency){
        BigDecimal platformPrice;
        BigDecimal total;
        Map<Object, Object> map = RedisUtil.hGetAll(ActivitySpoKeyConstants.Spot.NEW_PRICE);
        String temp = platformCurrency + "_usdt";
        Object object = map.get(temp);
        if (object == null) {
            platformPrice = BigDecimal.ONE;
        } else {
            NewPriceEntity priceEntity = JSON.parseObject(object.toString(), NewPriceEntity.class);
            platformPrice = priceEntity.getPrice();
        }
        if ("usdt".equals(currency)) {
            total = amount;
        } else if (symbol.endsWith("_usdt")) {
            String[] currencies = symbol.split("_");
            if (!currency.equals(currencies[0]) && !currency.equals(currencies[1])) {
                //                String market = currency + "_usdt";
                //                Object obj = map.get(market);
                //                if (obj == null) {
                //                    total = BigDecimal.ZERO;
                //                } else {
                //                    NewPriceEntity priceEntity = JSON.parseObject(obj.toString(), NewPriceEntity.class);
                //                    total = amount.multiply(priceEntity.getPrice());
                //                }
                total = BigDecimal.ZERO;
            } else {
                total = amount.multiply(price);
            }
        } else {
            String market = currency + "_usdt";
            Object obj = map.get(market);
            if (obj == null) {
                total = BigDecimal.ZERO;
            } else {
                NewPriceEntity priceEntity = JSON.parseObject(obj.toString(), NewPriceEntity.class);
                total = amount.multiply(priceEntity.getPrice());
            }
        }
        return total.divide(platformPrice, 16, RoundingMode.DOWN);
    }
}
